#pragma once
#include "stdafx.h"

/*
TODO:
Missing a user defined assignment operator to overload default assignment operator.

*/

class Manager;
class Object;

class Component 
{
private:
	// Set default constructor to private, never use default constructor.
	Component();

public:
	typedef boost::shared_ptr<Component> sPtr;
	typedef int CompId;

	explicit Component(const CompName name);

	virtual ~Component();

	//This function called by Manager in addedComponent function
	//Each component can regist message/component in the virtual
	//version of this function.
	virtual void AddedToObject()=0;

	//Add a new component which has the same object with this component.
	void AddLocalComponent(const CompPtr&);

	//Add a new component in Manager.
	void AddComponent(const ObjectName, const CompPtr &);

	//Regist a message request in Manager, use third parameter to
	//control request local/global message. In local model, only receive
	//other component message which has same object with this component
	//In global model, receive all other components message in Manager.
	void RequestMessage(const MsgId &, MessageFunction, bool);

	//Regist a component request in Manager, use third parameter to
	//control request local/global component. In local model, only receive
	//message when a request component add to same object with this component.
	//In global model, receive message when request component added in Manager.
	void RequestComponent(const CompName &, MessageFunction,bool);

	//Template function used to translate member function to MessageFunction
	template<class T>
	void RequestMessage(const MsgId &, void (T::*f)(Message const &), bool local = false);

	//Template function used to translate member function to MessageFunction
	template<class T>
	void RequestComponent(const CompName &, void (T::*f)(Message const &), bool local = false);

	//Send a global message to other component.
	void SendMessage(const MsgId &, const boost::any  payload = 0);

	//Send a local message to an specific object.
	void SendMessageToObject(const ObjectName &, const MsgId &, const boost::any payload = 0);

	//Send a local message in this component's object.
	void SendLocalMessage(const MsgId &, const boost::any payload = 0);

	// get object manager this component belongs to
	/*	inline Manager* getObjectManager() const
	{
	return m_manager;
	}*/

	//Get the name of this component's object 
	ObjectName GetOwnerId() const;

	//Get the name of this component 
	CompName GetName() const;

	//Get the id of this component 
	CompId GetId() const;

	//abandon?
	bool IsValid() const;

	bool operator == (const Component& c) const
	{
		return m_id == c.GetId();
	}

	bool operator == (const CompId& c) const
	{
		return m_id ==c;
	}

#ifdef _DEBUG
	stringstream Dump();
#endif

private:
	//abandon?
	void DestoryComponent();

	//Set the object name in this component, 
	//This function only called by Manager when component added.
	void setOwner(const ObjectName id);

	//Object name
	ObjectName m_ownerId;

	//The pointer of Manager, no need use smart pointer
	Manager* m_manager;

	//The id of this component
	CompId m_id;

	//The name of this component
	CompName m_name;

	//abandon?
	bool m_valid;

	// object manager is our friend
	friend class Manager;

};

// message request function
template<class T>
void Component::RequestMessage(const MsgId& message, void (T::*f)(Message const &),bool local) 
{
	RequestMessage(message, boost::bind(f, (T*)(this), _1),local);
}

// register a component request
template<class T>
void Component::RequestComponent(const CompName& name, void (T::*f)(Message const &), bool local) 
{
	RequestComponent(name, boost::bind(f, (T*)(this), _1), local);
}